component persistent="true"
{
	property name="MySCFID" fieldtype="id" generator="identity";

	property name="Username" required="true";
	property name="Password" required="true";
	property name="Salt" required="true";

	property name="FirstName" required="true";
	property name="MiddleName";
	property name="LastName" required="true";
	property name="Suffix";
	property name="PreferredName";
	property name="Email" required="true";
	property name="SSN";
	property name="isMale";
	property name="BirthDate" type="date";
	property name="Status" default=0;

	property name="Ethnicity" cfc="ethnicity" fieldtype="one-to-one"
		fkcolumn="EthnicityID" lazy="true" fetch="join"
		missingrowIgnored=true;


	public void function setFirstName(String firstname)
	{
		if(Len(ARGUMENTS.firstname) LT 1){
			throw("First name cannot be left blank");
		} else if(Len(ARGUMENTS.firstname) GT 50){
			throw("Maximum allowed length of first name is 50 characters");
		}

		VARIABLES.FirstName = ARGUMENTS.firstname;
	}


	public void function setLastName(String lastname)
	{
		if(Len(ARGUMENTS.lastname) LT 1){
			throw("Last name cannot be left blank");
		} else if(Len(ARGUMENTS.lastname) GT 50){
			throw("Maximum allowed length of last name is 50 characters");
		}

		VARIABLES.LastName = ARGUMENTS.lastname;
	}


	public void function setEmail(String email)
	{
		if(Len(ARGUMENTS.email) LT 1){
			throw("Email cannot be left blank");
		} else if(Len(ARGUMENTS.email) GT 100){
			throw("Maximum allowed length of email is 100 characters");
		}

		VARIABLES.Email = ARGUMENTS.email;
	}


	public void function setUsername(String username)
	{
		if(Len(ARGUMENTS.username) LT 4 OR Len(ARGUMENTS.username) GT 12){
		 	throw("Username must be between 4 and 12 characters in length");
		} else if(REFindNoCase('[^a-z0-9]', ARGUMENTS.username)){
			throw("Usernames may only be composed of letters or numbers");
		} else {
			LOCAL.mobj = EntityLoad("mySCF", {'username' = ARGUMENTS.username}, true);
			if(isDefined("LOCAL.mobj")){
				throw(ARGUMENTS.username & " not available");
			}
		}

		VARIABLES.Username = ARGUMENTS.username;
	}


	public void function setPassword(String password)
	{
		if(Len(ARGUMENTS.password) LT 6){
			throw("Minimum password length is 6 characters");
		} else if(Len(ARGUMENTS.password) GT 50){
			throw("Maximum password length is 50 characters");
		}

		if(!isDefined("VARIABLES.Salt") || VARIABLES.Salt EQ ""){
			THIS.generateSalt();
		}

		VARIABLES.Password = Hash(
			(VARIABLES.Salt & ARGUMENTS.password),
			'SHA-512'
		);
	}


	public void function setSalt(String salt)
	{
		throw("MySCF.setSalt() cannot be called directly - use MySCF.generateSalt()");
	}


	public void function generateSalt()
	{
		LOCAL.count = RandRange(64,128,"SHA1PRNG");
		VARIABLES.Salt = '';
		for(LOCAL.i = 1; LOCAL.i < LOCAL.count; LOCAL.i++){
			VARIABLES.Salt &= Chr(RandRange(32,126,"SHA1PRNG"));
		}
	}


	public boolean function verifyPassword(String password)
	{
		LOCAL.Password = Hash(
			(VARIABLES.Salt & ARGUMENTS.password),
			'SHA-512'
		);

		if(LOCAL.Password EQ VARIABLES.Password){ return true; }

		return false;
	}
}